package com.jetwinner.webfast.mvc.controller;

import com.jetwinner.toolbag.ArrayToolkit;
import com.jetwinner.util.*;
import com.jetwinner.webfast.kernel.AppUser;
import com.jetwinner.webfast.kernel.Paginator;
import com.jetwinner.webfast.kernel.dao.support.OrderBy;
import com.jetwinner.webfast.kernel.service.AppUserService;
import com.jetwinner.webfast.kernel.typedef.ParamMap;
import com.jetwinner.webfast.module.bigapp.service.AppGroupService;
import com.jetwinner.webfast.module.bigapp.service.AppGroupThreadService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

import static com.jetwinner.webfast.mvc.BaseControllerHelper.createMessageResponse;
import static com.jetwinner.webfast.mvc.BaseControllerHelper.setFlashMessage;

/**
 * @author xulixin
 */
@Controller("webfastSiteGroupThreadController")
public class GroupThreadController {

    private final AppGroupService groupService;
    private final AppGroupThreadService threadService;
    private final AppUserService userService;

    public GroupThreadController(AppGroupService groupService,
                                 AppGroupThreadService threadService,
                                 AppUserService userService) {

        this.groupService = groupService;
        this.threadService = threadService;
        this.userService = userService;
    }

    @RequestMapping("/group/{id}/thread/create")
    public ModelAndView addThreadAction(@PathVariable Integer id, HttpServletRequest request) {
        AppUser user = AppUser.getCurrentUser(request);

        Map<String, Object> groupinfo = groupService.getGroup(id);
        if (MapUtil.isEmpty(groupinfo)) {
            return createMessageResponse("info", "该小组已被关闭");
        }
        if (this.getGroupMemberRole(id, user) == 0) {
            return createMessageResponse("info", "只有小组成员可以发言");
        }

        if ("POST".equalsIgnoreCase(request.getMethod())) {
            Map<String, Object> threadData = ParamMap.toFormDataMap(request);

            String title = String.valueOf(threadData.get("thread[title']"));
            if (EasyStringUtil.isBlank(title)) {
                setFlashMessage("danger", "话题名称不能为空！", request.getSession());

                return new ModelAndView("/group/add-thread")
                        .addObject("id", id)
                        .addObject("groupinfo", groupinfo)
                        .addObject("is_groupmember", this.getGroupMemberRole(id, user));
            }

            Map<String, Object> info = FastHashMap.build(4)
                    .add("title", threadData.get("thread[title]"))
                    .add("content", threadData.get("thread[content]"))
                    .add("groupId", id)
                    .add("userId", user.getId()).toMap();

            Map<String, Object> thread = threadService.addThread(info);

            if (threadData.containsKey("file")) {
                Object file = threadData.get("file");
                // threadService.addAttach(file, thread.get("id"));
            }

            ;
            return new ModelAndView("redirect:" +
                    String.format("/group/%d/thread/%s", id, thread.get("id")));

        }
        return new ModelAndView("/group/add-thread")
                .addObject("id", id)
                .addObject("groupinfo", groupinfo)
                .addObject("is_groupmember", this.getGroupMemberRole(id, user));
    }

    private Integer getGroupMemberRole(Integer groupId, AppUser user) {
        if (user.getId() == null) {
            return 0;
        }
        if (groupService.isOwner(groupId, user.getId())) {
            return 2;
        }
        if (groupService.isAdmin(groupId, user.getId())) {
            return 3;
        }
        if (groupService.isMember(groupId, user.getId())) {
            return 1;
        }

        return 0;
    }

    @RequestMapping("/group/{id}/search")
    public ModelAndView searchResultAction(@PathVariable Integer id, HttpServletRequest request) {
        String keyWord = request.getParameter("keyWord");
        Map<String, Object> group = groupService.getGroup(id);

        Paginator paginator = new Paginator(request,
                threadService.searchThreadsCount(FastHashMap.build(2).add("status", "open")
                        .add("title", keyWord).add("groupId", id).toMap()),
                15);
        List<Map<String, Object>> threads = threadService.searchThreads(FastHashMap.build(2).add("status", "open")
                        .add("title", keyWord).add("groupId", id).toMap(),
                OrderBy.build(1).addDesc("createdTime"),
                paginator.getOffsetCount(),
                paginator.getPerPageCount());

        Set<Object> ownerIds = ArrayToolkit.column(threads, "userId");

        Set<Object> userIds = ArrayToolkit.column(threads, "lastPostMemberId");

        Map<String, AppUser> owner = userService.findUsersByIds(ownerIds);

        Map<String, AppUser> lastPostMembers = userService.findUsersByIds(userIds);

        return new ModelAndView("/group/group-search-result")
                .addObject("groupinfo", group)
                .addObject("threads", threads)
                .addObject("owner", owner)
                .addObject("paginator", paginator)
                .addObject("lastPostMembers", lastPostMembers)
                .addObject("is_groupmember",
                        this.getGroupMemberRole(id, AppUser.getCurrentUser(request)));
    }

    @RequestMapping("/group/{id}/thread/{threadId}")
    public ModelAndView groupThreadIndexAction(@PathVariable Integer id,
                                               @PathVariable Integer threadId,
                                               HttpServletRequest request) {

        Map<String, Object> group = groupService.getGroup(id);
        if ("close".equalsIgnoreCase(String.valueOf(group.get("status")))) {
            return createMessageResponse("info", "该小组已被关闭");
        }

        AppUser user = AppUser.getCurrentUser(request);

        Map<String, Object> threadMain = threadService.getThread(threadId);
        if (MapUtil.isEmpty(threadMain)) {
            return createMessageResponse("info", "该话题已被管理员删除");
        }

        if ("close".equalsIgnoreCase(String.valueOf(threadMain.get("status")))) {
            return createMessageResponse("info", "该话题已被关闭");
        }

        boolean isCollected = false;
        if (!"close".equalsIgnoreCase(String.valueOf(threadMain.get("status")))) {
            isCollected = threadService.isCollected(user.getId(), threadMain.get("id"));
        }

        threadService.waveHitNum(threadId);

        if (EasyStringUtil.isNotBlank(request.getParameter("post"))) {
            String url = this.getPost(request.getParameter("post"), threadId, id);
            return new ModelAndView("redirect:/" + url);
        }

        AppUser owner = userService.getUser(threadMain.get("userId"));

        Map<String, String> filters = this.getPostSearchFilters(request);

        Map<String, Object> condition = this.getPostCondition(filters.get("type"),
                threadMain.get("userId"), threadId);

        OrderBy sort = this.getPostOrderBy(filters.get("sort"));

        int postCount = threadService.searchPostsCount(condition);

        Paginator paginator = new Paginator(request, postCount, 30);

        List<Map<String, Object>> post = threadService.searchPosts(condition, sort,
                paginator.getOffsetCount(), paginator.getPerPageCount());

        Set<Object> postMemberIds = ArrayToolkit.column(post, "userId");

        Set<Object> postIds = ArrayToolkit.column(post, "id");

        Set<Object> postReplyAll = new HashSet<>();
        Map<String, Object> postReply = new HashMap<>();
        Map<String, Object> postReplyCount = new HashMap<>();
        Map<String, Object> postReplyPaginator = new HashMap<>();
        Map<String, Object> postFiles = new HashMap<>();
        Map<String, Object> postAttachs = new HashMap<>();
        for (Object postId : postIds) {
            String value = String.valueOf(postId);
            int replyCount = threadService.searchPostsCount(FastHashMap.build(1).add("postId", value).toMap());
            Paginator replyPaginator = new Paginator(request, replyCount, 10);

            List<Map<String, Object>> reply = threadService.searchPosts(FastHashMap.build(1).add("postId", value).toMap(),
                    OrderBy.build(1).addDesc("createdTime"),
                    replyPaginator.getOffsetCount(),
                    replyPaginator.getPerPageCount());

            postReplyCount.put(value, replyCount);
            postReply.put(value, reply);
            postReplyPaginator.put(value, replyPaginator);

            if (ListUtil.isNotEmpty(reply)) {
                postReplyAll.addAll(ArrayToolkit.column(reply, "userId"));
            }

            List<Map<String, Object>> attachs = threadService.searchGoods(
                    FastHashMap.build(2).add("postId", value).add("type", "postAttachment").toMap(),
                    OrderBy.build(1).addDesc("createdTime"), 0, 1000);

            Set<Object> postFileIds = ArrayToolkit.column(attachs, "fileId");

            // :TODO fileService is not finished.
//            postFiles.put(value, fileService.getFilesByIds(postFileIds));
            postAttachs.put(value, attachs);
        }

        Map<String, AppUser> postReplyMembers = userService.findUsersByIds(postReplyAll);
        Map<String, AppUser> postMember = userService.findUsersByIds(postMemberIds);

        List<Map<String, Object>> activeMembers = groupService.searchMembers(
                FastHashMap.build(1).add("groupId", id).toMap(),
                OrderBy.build(1).addDesc("postNum"), 0, 12);

        Set<Object> memberIds = ArrayToolkit.column(activeMembers, "userId");
        Map<String, AppUser> members = userService.findUsersByIds(memberIds);

        List<Map<String, Object>> isAdopt = threadService.searchPosts(
                FastHashMap.build(2).add("adopt", 1).add("threadId", threadId).toMap(),
                OrderBy.build(1).addDesc("createdTime"), 0, 1);

        this.hideThings(threadMain, user);

        List<Map<String, Object>> attachs = threadService.searchGoods(
                FastHashMap.build(2).add("threadId", threadMain.get("id")).add("type", "attachment").toMap(),
                OrderBy.build(1).addDesc("createdTime"), 0, 1000);

        Set<Object> fileIds = ArrayToolkit.column(attachs, "fileId");

        return new ModelAndView("/group/thread")
                .addObject("groupinfo", group)
                .addObject("isCollected", isCollected)
                .addObject("threadMain", threadMain)
                .addObject("user", user)
                .addObject("owner", owner)
                .addObject("post", post)
                .addObject("paginator", paginator)
                .addObject("postMember", postMember)
                .addObject("filters", filters)
                .addObject("postCount", postCount)
                .addObject("postReply", postReply)
                .addObject("activeMembers", activeMembers)
                .addObject("postReplyMembers", postReplyMembers)
                .addObject("members", members)
                .addObject("postReplyCount", postReplyCount)
                .addObject("postReplyPaginator", postReplyPaginator)
                .addObject("isAdopt", isAdopt)
                .addObject("attachs", attachs)
//                .addObject("files", fileService.getFilesByIds(fileIds))
                .addObject("postFiles", postFiles)
                .addObject("postAttachs", postAttachs)
                .addObject("is_groupmember", this.getGroupMemberRole(id, user));
    }

    private String getPost(String postId, Integer threadId, Integer id) {
        int count = threadService.searchPostsCount(
                FastHashMap.build(2).add("threadId", threadId).add("status", "open")
                        .add("id", postId).add("postId", 0).toMap());
        int page = (int) (Math.floor(count / 30)) + 1;

        StringBuilder url = new StringBuilder("/group/").append(id).append("thread/").append(threadId);
        url.append("?page=").append(page).append("#post-").append(postId);
        return url.toString();
    }

    private Map<String, String> getPostSearchFilters(HttpServletRequest request) {
        Map<String, String> filters = new HashMap<>(2);

        filters.put("type", request.getParameter("type"));

        if (!ArrayUtil.inArray(filters.get("type"), "all", "onlyOwner")) {
            filters.put("type", "all");
        }

        filters.put("sort", request.getParameter("sort"));

        if (!ArrayUtil.inArray(filters.get("sort"), "asc", "desc")) {
            filters.put("sort", "asc");
        }

        return filters;
    }

    private Map<String, Object> getPostCondition(String filterType, Object ownId, Integer threadId) {
        if ("all".equalsIgnoreCase(filterType)) {
            return FastHashMap.build(3).add("threadId", threadId)
                    .add("status", "open").add("postId", 0).toMap();
        }

        if ("onlyOwner".equalsIgnoreCase(filterType)) {
            return FastHashMap.build(3).add("threadId", threadId)
                    .add("status", "open").add("userId", ownId).add("postId", 0).toMap();
        }

        return FastHashMap.build(0).toMap();

    }

    private OrderBy getPostOrderBy(String sort) {
        if ("desc".equalsIgnoreCase(sort)) {
            return OrderBy.build(1).addDesc("createdTime");
        } else {
            return OrderBy.build(1).add("createdTime");
        }
    }

    public void hideThings(Map<String, Object> thread, AppUser user) {
        String strThreadContent = String.valueOf(thread.get("content"));
        strThreadContent = strThreadContent.replace("#", "<!--></>");
        strThreadContent = strThreadContent.replace("[hide=reply", "#[hide=reply");
        strThreadContent = strThreadContent.replace("[hide=coin", "#[hide=coin");
        thread.put("content", strThreadContent);
        String[] data = strThreadContent.split("[/hide]");

        int role = this.getGroupMemberRole(ValueParser.toInteger(thread.get("groupId")), user);
        int count = 0;

        StringBuilder context = new StringBuilder();
        for (String value : data) {

            Map<String, String> args = new HashMap<>(5);
            // sscanf($value, "%[^#]#[hide=coin%[^]]]%[^$$]", $content, $coin, $hideContent);
            // sscanf($value, "%[^#]#[hide=reply]%[^$$]", $replyContent, $replyHideContent);
            String content = args.get("content");
            String coin = args.get("coin");
            String hideContent = args.get("hideContent");
            String replyContent = args.get("replyContent");
            String replyHideContent = args.get("replyHideContent");

            Map<String, Object> Trade = threadService.getTradeByUserIdAndThreadId(user.getId(), thread.get("id"));

            if (role == 2 || role == 3 || ValueParser.intValueEquals(user.getId(), thread.get("userId")) ||
                    MapUtil.isNotEmpty(Trade)) {

                if (EasyStringUtil.isNotBlank(coin)) {

                    if (role == 2 || role == 3 || ValueParser.intValueEquals(user.getId(), thread.get("userId"))) {

                        context.append(content)
                                .append("<div class=\"hideContent mtl mbl clearfix\"><span class=\"pull-right\" style='font-size:10px;'>隐藏区域</span>")
                                .append(hideContent).append("</div>");

                    } else {
                        context.append(content).append(hideContent);
                    }

                } else {
                    context.append(content);
                }
            } else {
                if (EasyStringUtil.isNotBlank(coin)) {

                    count = 1;
                    if (user.getId() > 0) {
                        context.append(content)
                                .append("<div class=\"hideContent mtl mbl\"><h4> <a href=\"javascript:\" data-toggle=\"modal\" data-target=\"#modal\" data-urL=\"/thread/{$thread['id']}/hide\">点击查看</a>本话题隐藏内容</h4></div>");
                    } else {
                        context.append(content)
                                .append("<div class=\"hideContent mtl mbl\"><h4> 游客,如果您要查看本话题隐藏内容请先<a href=\"/login\">登录</a>或<a href=\"/register\">注册</a>！</h4></div>");
                    }

                } else {
                    context.append(content);
                }
            }

            if (EasyStringUtil.isNotBlank(replyHideContent)) {
                context.append(this.replyCanSee(role, thread, content, replyHideContent, user));
            }
        }

        if (context.length() > 0) {
            thread.put("content", context.toString());
        }

        thread.put("count", count);

        thread.put("content", String.valueOf(thread.get("content")).replace("<!--></>", "#"));
    }

    private String replyCanSee(int role, Map<String, Object> thread, String content, String replyHideContent,
                               AppUser user) {

        StringBuilder context = new StringBuilder();
        if (EasyStringUtil.isNotBlank(replyHideContent)) {

            if (role == 2 || role == 3 || ValueParser.intValueEquals(user.getId(), thread.get("userId"))) {

                context.append(content)
                        .append("<div class=\"hideContent mtl mbl clearfix\"><span class=\"pull-right\" style='font-size:10px;'>回复可见区域</span>")
                        .append(replyHideContent).append("</div>");

                return context.toString();
            }

            if (user.getId() == null || user.getId() < 1) {
                context.append(content)
                        .append("<div class=\"hideContent mtl mbl\"><h4> 游客,如果您要查看本话题隐藏内容请先<a href=\"/login\">登录</a>或<a href=\"/register\">注册</a>！</h4></div>");
                return context.toString();
            }

            int count = threadService.searchPostsCount(FastHashMap.build(2).add("userId", user.getId())
                    .add("threadId", thread.get("id")).toMap());

            if (count > 0) {
                context.append(content).append(replyHideContent);
            } else {
                context.append(content)
                        .append("<div class=\"hideContent mtl mbl\"><h4> <a href=\"#post-thread-form\">回复</a>本话题可见</h4></div>");
            }
        }
        return context.toString();
    }
}
